/* @flow */

import { cloneVNode, cloneVNodes } from 'core/vdom/vnode'

/**
 * Runtime helper for rendering static trees.
 * 什么是静态树？
 * 答：静态树就是整个树中，所有的ASTNode节点的static属性为true，
 * 也就是说，该树中的所有节点都不会再变化，在重渲染时，无需关注这些节点。
 * 也就是说，如果是静态树中的节点，则不需要重复使用createElement方法创建vnode对象，
 * 而是只进行简单的拷贝即可。
 * 详情可见flow/compiler.js下的关于static的解释
 */
export function renderStatic (
  index: number,
  //该属性用于标记静态元素是否在v-for指令的影响范围内，
  //如果在v-for的影响范围内，则也需要每次都创建新的vnode对象，而不仅仅是clone。
  //具体可查看compiler.js下的关于staticInFor属性的注释
  //@todo 为什么在v-for范围内就需要每次都创建新的vnode对象？
  isInFor?: boolean
): VNode | Array<VNode> {
  let tree = this._staticTrees[index]
  // if has already-rendered static tree and not inside v-for,
  // we can reuse the same tree by doing a shallow clone.
  //对于静态树，只在初次渲染时进行解析，而重渲染时，只需简单的浅拷贝。
  //@todo 为什么要进行浅拷贝？
  //猜测：应该是因为一个vnode对象只能被使用一次吧。
  if (tree && !isInFor) {
    return Array.isArray(tree)
      ? cloneVNodes(tree)
      : cloneVNode(tree)
  }
  // otherwise, render a fresh tree.
  tree = this._staticTrees[index] =
    this.$options.staticRenderFns[index].call(this._renderProxy)
  markStatic(tree, `__static__${index}`, false)
  return tree
}

/**
 * Runtime helper for v-once.
 * Effectively it means marking the node as static with a unique key.
 */
export function markOnce (
  tree: VNode | Array<VNode>,
  index: number,
  key: string
) {
  markStatic(tree, `__once__${index}${key ? `_${key}` : ``}`, true)
  return tree
}

//该方法用于为虚拟dom tree设置isStatic、key和isOnce属性
function markStatic (
  tree: VNode | Array<VNode>,
  key: string,
  isOnce: boolean
) {
  if (Array.isArray(tree)) {
    for (let i = 0; i < tree.length; i++) {
      if (tree[i] && typeof tree[i] !== 'string') {
        markStaticNode(tree[i], `${key}_${i}`, isOnce)
      }
    }
  } else {
    markStaticNode(tree, key, isOnce)
  }
}

function markStaticNode (node, key, isOnce) {
  node.isStatic = true
  node.key = key
  node.isOnce = isOnce
}
